﻿using System;
using System.Collections.Generic;
using System.Xml;

namespace FrontEnd.Storage
{
    ///-------------------------------------------------------------------------------------------------
    /// <summary> Stores information about single emulator. </summary>
    ///-------------------------------------------------------------------------------------------------
    public class Emulator
    {
        #region Xml Constants

        private const String EXECUTABLE_PATH_NODE = "ExecutablePath";
        private const String ROM_PATH_NODE = "RomPath";
        private const String DATA_FOLDER_NAME_ATTR = "DataFolderName";
        private const String ARTWORK_NODE = "Artwork";
        private const String FOLDER_NODE = "Folder";
        private const String TYPE_ATTR = "Type";

        #endregion

        #region Properties

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the full path to the emulator executable. If not set, we'll assume the
        /// roms themselves are exectauble (e.g. batch files.) </summary>
        /// <value> The full path to the executable. </value>
        ///-------------------------------------------------------------------------------------------------
        public String ExecutablePath { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the full path to the roms. </summary>
        /// <value> The full path to the roms. </value>
        ///-------------------------------------------------------------------------------------------------
        public String RomPath { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the name of the sub-folder where game lists and layouts will be stored. </summary>
        /// <value> The data folder. </value>
        ///-------------------------------------------------------------------------------------------------
        public String DataFolderName { get; set; }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets or sets the artwork folder paths, which should sync up with the current layout. </summary>
        /// <value> The artwork folder paths. </value>
        ///-------------------------------------------------------------------------------------------------
        public Dictionary<String, ArtworkType> ArtworkFolderPaths { get; private set; }

        #endregion

        #region Constructor(s)

        /// <summary> Default constructor. </summary>
        public Emulator()
        {
            Init();
            Clear();
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Constructor. </summary>
        /// <param name="node"> The node to load from. </param>
        ///-------------------------------------------------------------------------------------------------
        public Emulator(XmlNode node)
        {
            Init();
            LoadFrom(node);
        }

        /// <summary> Initialises this object. </summary>
        private void Init()
        {
            ArtworkFolderPaths = new Dictionary<string, ArtworkType>(StringComparer.OrdinalIgnoreCase);
        }

        #endregion

        #region Public

        /// <summary> Clears this object to its blank/initial state. </summary>
        public void Clear()
        {
            ExecutablePath = null;
            RomPath = null;
            DataFolderName = null;
            ArtworkFolderPaths.Clear();
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Saves to the node. </summary>
        /// <exception cref="ArgumentNullException"> Thrown when one or more required arguments are null. </exception>
        /// <param name="node"> The node to save to. </param>
        ///-------------------------------------------------------------------------------------------------
        public void SaveTo(XmlNode node)
        {
            if (node == null)
                throw new ArgumentNullException("node");

            XmlNode executableNode = node.OwnerDocument.CreateElement(EXECUTABLE_PATH_NODE);
            executableNode.InnerText = String.IsNullOrWhiteSpace(ExecutablePath) ? "" : ExecutablePath;
            node.AppendChild(executableNode);

            XmlNode romNode = node.OwnerDocument.CreateElement(ROM_PATH_NODE);
            romNode.InnerText = String.IsNullOrWhiteSpace(RomPath) ? "" : RomPath;
            node.AppendChild(romNode);

            XmlAttribute attr = node.OwnerDocument.CreateAttribute(DATA_FOLDER_NAME_ATTR);
            attr.Value = String.IsNullOrWhiteSpace(DataFolderName) ? "" : DataFolderName;
            node.Attributes.Append(attr);

            XmlNode artworkParentNode = node.OwnerDocument.CreateElement(ARTWORK_NODE);
            node.AppendChild(artworkParentNode);

            foreach (KeyValuePair<String, ArtworkType> artworkFolderInfo in ArtworkFolderPaths)
            {
                XmlNode folderNode = node.OwnerDocument.CreateElement(FOLDER_NODE);
                folderNode.InnerText = artworkFolderInfo.Key;
                artworkParentNode.AppendChild(folderNode);

                XmlAttribute typeAttr = node.OwnerDocument.CreateAttribute(TYPE_ATTR);
                typeAttr.Value = artworkFolderInfo.Value.ToString();
                folderNode.Attributes.Append(typeAttr);
            }
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Loads from the node. </summary>
        /// <exception cref="ArgumentNullException"> Thrown when one or more required arguments are null. </exception>
        /// <param name="node"> The node to load from. </param>
        ///-------------------------------------------------------------------------------------------------
        public void LoadFrom(XmlNode node)
        {
            if (node == null)
                throw new ArgumentNullException("node");

            ExecutablePath = node.SelectSingleNode(EXECUTABLE_PATH_NODE).InnerText;
            RomPath = node.SelectSingleNode(ROM_PATH_NODE).InnerText;
            DataFolderName = node.Attributes[DATA_FOLDER_NAME_ATTR].Value;

            ArtworkFolderPaths.Clear();
            foreach (XmlNode folderNode in node.SelectSingleNode(ARTWORK_NODE).SelectNodes(FOLDER_NODE))
            {
                ArtworkFolderPaths.Add(folderNode.InnerText, (ArtworkType)Enum.Parse(typeof(ArtworkType), 
                    folderNode.Attributes[TYPE_ATTR].Value, true));
            }
        }

        #endregion
    }
}
